#!/usr/bin/env bash

[[ "$@" =~ --pre ]] && version=0.10.6 pre=1 ||
                       version=0.10.6 pre=0

cd $(dirname $BASH_SOURCE)
fzf_base=$(pwd)

# If stdin is a tty, we are "interactive".
[ -t 0 ] && interactive=yes

ask() {
  # non-interactive shell: wait for a linefeed
  #     interactive shell: continue after a single keypress
  [ -n "$interactive" ] && read_n='-n 1' || read_n=

  read -p "$1 ([y]/n) " $read_n -r
  echo
  [[ ! $REPLY =~ ^[Nn]$ ]]
}

check_binary() {
  echo -n "  - Checking fzf executable ... "
  local output
  output=$("$fzf_base"/bin/fzf --version 2>&1)
  if [ $? -ne 0 ]; then
    echo "Error: $output"
    binary_error="Invalid binary"
  elif [ "$version" != "$output" ]; then
    echo "$output != $version"
    binary_error="Invalid version"
  else
    echo "$output"
    binary_error=""
    return 0
  fi
  rm -f "$fzf_base"/bin/fzf
  return 1
}

symlink() {
  echo "  - Creating symlink: bin/$1 -> bin/fzf"
  (cd "$fzf_base"/bin &&
   rm -f fzf &&
   ln -sf $1 fzf)
  if [ $? -ne 0 ]; then
    binary_error="Failed to create symlink"
    return 1
  fi
}

download() {
  echo "Downloading bin/fzf ..."
  if [ $pre = 0 ]; then
    if [ -x "$fzf_base"/bin/fzf ]; then
      echo "  - Already exists"
      check_binary && return
    elif [ -x "$fzf_base"/bin/$1 ]; then
      symlink $1 && check_binary && return
    fi
  fi
  mkdir -p "$fzf_base"/bin && cd "$fzf_base"/bin
  if [ $? -ne 0 ]; then
    binary_error="Failed to create bin directory"
    return
  fi

  local url=https://github.com/junegunn/fzf-bin/releases/download/$version/${1}.tgz
  if which curl > /dev/null; then
    curl -fL $url | tar -xz
  elif which wget > /dev/null; then
    wget -O - $url | tar -xz
  else
    binary_error="curl or wget not found"
    return
  fi

  if [ ! -f $1 ]; then
    binary_error="Failed to download ${1}"
    return
  fi

  chmod +x $1 && symlink $1 && check_binary
}

# Try to download binary executable
archi=$(uname -sm)
binary_available=1
binary_error=""
case "$archi" in
  Darwin\ x86_64) download fzf-$version-darwin_amd64 ;;
  Darwin\ i*86)   download fzf-$version-darwin_386   ;;
  Linux\ x86_64)  download fzf-$version-linux_amd64  ;;
  Linux\ i*86)    download fzf-$version-linux_386    ;;
  *)              binary_available=0 binary_error=1  ;;
esac

cd "$fzf_base"
if [ -n "$binary_error" ]; then
  if [ $binary_available -eq 0 ]; then
    echo "No prebuilt binary for $archi ... "
  else
    echo "  - $binary_error !!!"
    exit 1
  fi
  echo "Installing legacy Ruby version ..."

  # ruby executable
  echo -n "Checking Ruby executable ... "
  ruby=`which ruby`
  if [ $? -ne 0 ]; then
    echo "ruby executable not found !!!"
    exit 1
  fi

  # System ruby is preferred
  system_ruby=/usr/bin/ruby
  if [ -x $system_ruby -a $system_ruby != "$ruby" ]; then
    $system_ruby --disable-gems -rcurses -e0 2> /dev/null
    [ $? -eq 0 ] && ruby=$system_ruby
  fi

  echo "OK ($ruby)"

  # Curses-support
  echo -n "Checking Curses support ... "
  "$ruby" -rcurses -e0 2> /dev/null
  if [ $? -eq 0 ]; then
    echo "OK"
  else
    echo "Not found"
    echo "Installing 'curses' gem ... "
    if (( EUID )); then
      /usr/bin/env gem install curses --user-install
    else
      /usr/bin/env gem install curses
    fi
    if [ $? -ne 0 ]; then
      echo
      echo "Failed to install 'curses' gem."
      if [[ $(uname -r) =~ 'ARCH' ]]; then
        echo "Make sure that base-devel package group is installed."
      fi
      exit 1
    fi
  fi

  # Ruby version
  echo -n "Checking Ruby version ... "
  "$ruby" -e 'exit RUBY_VERSION >= "1.9"'
  if [ $? -eq 0 ]; then
    echo ">= 1.9"
    "$ruby" --disable-gems -rcurses -e0 2> /dev/null
    if [ $? -eq 0 ]; then
      fzf_cmd="$ruby --disable-gems $fzf_base/fzf"
    else
      fzf_cmd="$ruby $fzf_base/fzf"
    fi
  else
    echo "< 1.9"
    fzf_cmd="$ruby $fzf_base/fzf"
  fi

  # Create fzf script
  echo -n "Creating wrapper script for fzf ... "
  rm -f "$fzf_base"/bin/fzf
  echo "#!/bin/sh" > "$fzf_base"/bin/fzf
  echo "$fzf_cmd \"\$@\"" >> "$fzf_base"/bin/fzf
  chmod +x "$fzf_base"/bin/fzf
  echo "OK"
fi

[[ "$*" =~ "--bin" ]] && exit 0

# Auto-completion
ask "Do you want to add auto-completion support?"
auto_completion=$?

# Key-bindings
ask "Do you want to add key bindings?"
key_bindings=$?

echo
for shell in bash zsh; do
  echo -n "Generate ~/.fzf.$shell ... "
  src=~/.fzf.${shell}

  fzf_completion="[[ \$- == *i* ]] && source \"$fzf_base/shell/completion.${shell}\" 2> /dev/null"
  if [ $auto_completion -ne 0 ]; then
    fzf_completion="# $fzf_completion"
  fi

  fzf_key_bindings="source \"$fzf_base/shell/key-bindings.${shell}\""
  if [ $key_bindings -ne 0 ]; then
    fzf_key_bindings="# $fzf_key_bindings"
  fi

  cat > $src << EOF
# Setup fzf
# ---------
if [[ ! "\$PATH" == *$fzf_base/bin* ]]; then
  export PATH="\$PATH:$fzf_base/bin"
fi

# Man path
# --------
if [[ ! "\$MANPATH" == *$fzf_base/man* && -d "$fzf_base/man" ]]; then
  export MANPATH="\$MANPATH:$fzf_base/man"
fi

# Auto-completion
# ---------------
$fzf_completion

# Key bindings
# ------------
$fzf_key_bindings

EOF
  echo "OK"
done

# fish
has_fish=0
if [ -n "$(which fish 2> /dev/null)" ]; then
  has_fish=1
  echo -n "Update fish_user_paths ... "
  fish << EOF
  echo \$fish_user_paths | grep $fzf_base/bin > /dev/null
  or set --universal fish_user_paths \$fish_user_paths $fzf_base/bin
EOF
  [ $? -eq 0 ] && echo "OK" || echo "Failed"

  mkdir -p ~/.config/fish/functions
  if [ -e ~/.config/fish/functions/fzf.fish ]; then
    echo -n "Remove unnecessary ~/.config/fish/functions/fzf.fish ... "
    rm -f ~/.config/fish/functions/fzf.fish && echo "OK" || echo "Failed"
  fi

  if [ $key_bindings -eq 0 ]; then
    echo -n "Symlink ~/.config/fish/functions/fzf_key_bindings.fish ... "
    ln -sf $fzf_base/shell/key-bindings.fish \
           ~/.config/fish/functions/fzf_key_bindings.fish && echo "OK" || echo "Failed"
  fi
fi

append_line() {
  set -e
  echo "Update $2:"
  echo "  - $1"
  [ -f "$2" ] || touch "$2"
  if [ $# -lt 3 ]; then
    line=$(\grep -nF "$1" "$2" | sed 's/:.*//' | tr '\n' ' ')
  else
    line=$(\grep -nF "$3" "$2" | sed 's/:.*//' | tr '\n' ' ')
  fi
  if [ -n "$line" ]; then
    echo "    - Already exists: line #$line"
  else
    echo >> "$2"
    echo "$1" >> "$2"
    echo "    + Added"
  fi
  echo
  set +e
}

echo
for shell in bash zsh; do
  append_line "[ -f ~/.fzf.${shell} ] && source ~/.fzf.${shell}" ~/.${shell}rc "~/.fzf.${shell}"
done

if [ $key_bindings -eq 0 -a $has_fish -eq 1 ]; then
  bind_file=~/.config/fish/functions/fish_user_key_bindings.fish
  append_line "fzf_key_bindings" "$bind_file"
fi

cat << EOF
Finished. Restart your shell or reload config file.
   source ~/.bashrc  # bash
   source ~/.zshrc   # zsh
EOF
[ $has_fish -eq 1 ] && echo "   fzf_key_bindings  # fish"; cat << EOF

Use uninstall script to remove fzf.

For more information, see: https://github.com/junegunn/fzf
EOF

